import { defineComponent, onMounted, ref, nextTick, computed, watch, readonly, onUnmounted, defineAsyncComponent, provide } from 'vue';
import './index.scss';
import LabelPrefixWraper from '../../basic/label-prefix-wraper';
import { createAiEditor } from './hocks/useEditor';
import useMappingProps from 't/common/hooks/useMappingProps';
import { useQuasar } from '@teld/q-components';
import TImagePreview from 't/bussiness/image-preview/Component.jsx';

import {
    commonProps,
    fixNameSpace,
    pickOwnForBasicComponent,
} from 't/common/utils';
import commentManage from './CommentManage';
import { isObject } from 'lodash';
import useEnv from 't/common/hooks/useEnv';
import { debounce } from 'lodash-es';

// const DraftEditor  = () => import('../comment/pc/draft-editor/index.vue')
export default defineComponent({
    components:{
        TImagePreview
    },
    props: {
        ...commonProps,
        ...LabelPrefixWraper,
        maxHeight: {
            default: 'auto',
            type: String,
        },
        minHeight: {
            default: '400px',
            type: String,
        },
        label: {
            default: '',
            type: String,
        },
        instanceCode: {
            default: '',
            type: String,
        },
        hideLabel: {
            default: false,
            type: Boolean,
        },
        required: {
            default: false,
            type: Boolean,
        },
        labelPosition: {
            type: String,
            default() {
                return 'top';
            },
        },
        'no-resize': {
            default: false,
            type: Boolean,
        },
        helpConf: Boolean,
        helpTooltip: String,
        helpPlacement: String,
        helpMore: String,
        helpMorePopup: String,
        helpMoreLinkHrefStatic: String,
        helpMoreLinkHrefExp: String,
        helpMoreLink: String,
        enableComment: {
            default: false,
            type: Boolean,
        },
        selectedToolbar: Array,
        isSimple: Boolean,
        dense: Boolean,
        queryAllComments: Function,
        commentDataSource: {
            default: '',
            type: String
        },
        customizeToolbar: {
            default: '0',
            type: [Boolean, String]
        },
        modelValue: {
            default: '',
            type: String
        },
        mapping_pid: String,
        mapping_avatar: String,
        mapping_content: String,
        placeholder: String,
        readonly: Boolean,
        /** 浏览/只读时仍显示工具栏-默认false不显示 */
        stillShowHeader: Boolean,
        disable: Boolean,
        autofocus: Boolean,
        rules: Array,
        maxLength: Number,
        maxLengthMsg: String,
        defaultValue: String,
        commentTag: String,
        billID: String,
        enableBottomComment: Boolean,
        mapping_reference: String,
        commentEnable: Boolean,
        //
        outlineVisible: Boolean,
        outlineIncludeLevels: {
          type: Array,
          default: () => [1, 2, 3, 4, 5, 6]
        },
        enableAi: {
          type: Boolean,
          default: false
        },
        aiRole: {
          type: String,
          default: ''
        },
        aiFormat: {
          type: String,
          default: ''
        },
        aiConstraints: {
          // type: [String, Array] as PropType<string | string[]>,
          type: [String, Array],
          default: ''
        },
        enableAiReference: {
          type: Boolean,
          default: false
        },
    },
    setup(props, { attrs, emit, expose, slots }) {
        const { isMobile } = useEnv();

        const isLoading = ref(false)
        const previewSrc = ref(false)
        const srcList = ref([])
        const tEditorRef = ref(null)
        const imagePreviewRef = ref(null)
        let $q = useQuasar();
        const aiEditorRef = ref(null);
        let aiEditorInstance = null;
        const deleteCommemtList = ref([])
        const addCommemtList = ref([])
        const allComments = ref([])
        const mappingData = {
            id: 'ID',
            pid: props.mapping_pid || "PId",
            account: 'CreatorName',
            avatar: props.mapping_avatar || "Avatar",
            content: props.mapping_content || "Content",
            createdAt: "CreateTime",
            reference: props.mapping_reference || "Reference"
        }
        let targetProxy = ''
        let isFirstLoad = true
        let delayList = {}
        onUnmounted(() => {
            for (let i in delayList) {
                window.clearTimeout(delayList[i])
                delayList[i] = null
            }
        })
        const editorText = ref('')
        const requiredError = computed(() => {
            const { required } = mappingProps;
            return (
                required && !editorText.value

            );
        });
        const setFocus = () => {
            aiEditorInstance.focus()
        }
        const hideComment = () => {
            if (!props.enableComment || !aiEditorRef.value) return
            aiEditorRef.value.querySelector('.aie-comment-container').style.display = 'none'
            // aiEditorRef.value.querySelector('.tiptap.ProseMirror.aie-content').parentElement.style.width = '100%';
        }
        const showComment = () => {
            if (!props.enableComment || !aiEditorRef.value) return
            aiEditorRef.value.querySelector('.aie-comment-container').style.display = 'block'
            // aiEditorRef.value.querySelector('.tiptap.ProseMirror.aie-content').parentElement.style.width = '80%';
        }
        const onChangeDoc = () => {
          if (mappingProps.enableComment) {
            if (commentStatus === 'show') {
              showComment()
            } else {
              hideComment()
            }
          }
        }
        function convertColwidthToStyle(html) {
            // return html.replace(/colwidth="(\d+)"/g, function (match, p1) {
            //     return 'style="width: ' + p1 + 'px;"';
            // });
            // 2025.4.16 解决replace处理造成的style丢失问题，取消replace反复替换处理
            return html;
        }
        function convertStyleWidthToColwidth(html) {
            // return html.replace(/<(td|col|th)[^>]*style="[^"]*width:\s*(\d+(\.\d+)?)px;?[^"]*"[^>]*>/g, function (match, p1, p2) {
            //     return match.replace(/style="[^"]*width:\s*\d+(\.\d+)?px;?[^"]*"/, `colwidth="${p2}"`);
            // });
            // 2025.4.16 解决replace处理造成的style丢失问题，取消replace反复替换处理
            return html;
        }

        const formatEditorData = data => {
            if (!data) return data
            var regex = /<span[^>]*class="dataColorMark"[^>]*>([^<]+)<\/span>/gi;
            // 执行匹配
            var matches = [];
            var match;
            while ((match = regex.exec(data)) !== null) {
                matches.push(match[0]);
            }
            let renderData = data.replace(/<p\s*\/>/g, '<p></p>');
            // 输出所有匹配结果
            if (matches.length > 0) {
                console.log('匹配到的标签列表:', matches);
                matches.forEach(item => {
                    renderData = renderData.replace(item, item.replace(/<span/ig, '<mark').replace(/<\/span>/ig, '</mark>'))
                })
            }
            console.log(convertStyleWidthToColwidth(renderData), 'renderData')
            return convertStyleWidthToColwidth(renderData)
        }
        const [mappingProps, mappingExpose] = useMappingProps(props, {
            hideComment,
            showComment,
            getInstance: () => {
                return aiEditorInstance;
            },
            setData: e => {

                aiEditorInstance.setContent(formatEditorData(e));
            },
            insertHTML: e => {
                aiEditorInstance.insert(e);
            },
            validate,
            resetValidation,
            saveEditor: () => {
                addCommemtList.value = addCommemtList.value.filter(item => !deleteCommemtList.value.some(jj => jj.id == item.id))
                if (addCommemtList.value && addCommemtList.value.length) {
                    try {
                        CDO.BatchCreate_Async(mappingProps.commentDataSource, addCommemtList.value.map(item => {
                            let res = {}
                            for (let i in item) {
                                if (mappingData[i]) {
                                    if (i == 'reference') {
                                        try {

                                            let reference = ''
                                            let all = document.querySelectorAll(`span[class*="${item.pid || item.id}"`)
                                            for (let i = 0; i < all.length; i++) {
                                                reference += all[i].innerText
                                            }
                                            res[mappingData[i]] = reference
                                        } catch (error) {

                                        }
                                    } else {
                                        res[mappingData[i]] = item[i]
                                    }

                                }

                            }
                            res.BillID = props.billID//_.get(window, props.billID) || props.billID || window?.LocalVars?.vardata?.ID || props.instanceCode
                            res.CommentTag = _.get(window, props.commentTag) || props.commentTag || props.instanceCode
                            return res
                        })).then(res => {
                            addCommemtList.value = []
                        })
                    } catch (error) {
                        console.log(error)
                    }

                }
                if (deleteCommemtList.value && deleteCommemtList.value.length) {
                    try {
                        CDO.BatchDelete_Async(mappingProps.commentDataSource, deleteCommemtList.value.map(item => {
                            return item.id
                        })).then(res => {
                            deleteCommemtList.value = []
                        })
                    } catch (error) {
                        console.log(error)
                    }

                }
            },
          focus: setFocus

        });

        // if(!mappingProps.modelValue&&mappingProps.defaultValue){
        //     emit('update:modelValue', mappingProps.defaultValue)
        //  }
        // 是否显示必填校验错误
        const displayedErrorHint = ref(false);
        // 错误提示内容
        const errorHint = ref('');
        // 是否超长错误
        const maxLengthError = computed(() => {
            const { maxLength } = mappingProps;

            return (
                !requiredError.value && maxLength > 0 && editorText.value.length > maxLength
            );
        });
        // 超长错误提示内容
        const maxLengthErrorHint = computed(() => {
            const { maxLength, maxLengthMsg } = mappingProps;
            return maxLengthMsg && maxLengthMsg.replace('${value}', maxLength).replace('$', maxLength);
        });
        // 必填校验，不能选0
        function validate() {
            const { requiredMessage } = mappingProps;
            if (requiredError.value) {
                if (mappingProps.rules && mappingProps.rules[0]) {
                    errorHint.value = mappingProps.rules[0]('')
                }

            } else if (maxLengthError.value) {
                errorHint.value = maxLengthErrorHint.value;
            } else {
                resetValidation()
            }
            displayedErrorHint.value = requiredError.value || maxLengthError.value;
            return !displayedErrorHint.value;
        }
        // 应该返回一个布尔值（或一个 resolve 布尔值的 Promise）
        function resetValidation() {
            displayedErrorHint.value = false;
        }
        function onChange(aiEditor) {
            const { maxLength } = mappingProps;
            let val = aiEditor.getText()
            if ((maxLength > 0 && val.length > maxLength)) {
                const { modelValue } = mappingProps;
                Funcs.Notify('', maxLengthErrorHint.value, 'warning');
                targetProxy = convertColwidthToStyle(val.slice(0, maxLength).replace(/<mark/ig, '<span').replace(/<\/mark>/ig, '</span>'))
                emit('update:modelValue', targetProxy)

                aiEditor.setContent(formatEditorData(targetProxy))
                return
            }
            if (val) {
                validate()
            }

            if (aiEditor.getHtml() == targetProxy) return
            targetProxy = aiEditor.getHtml().replace(/<mark/ig, '<span').replace(/<\/mark>/ig, '</span>')
            emit('update:modelValue', convertColwidthToStyle(targetProxy));
            emit('change')
            editorText.value = val
        }
        function onBlur() {
            validate()
        }
        expose(mappingExpose);
        const setEditorHeight = () => {
            if (!aiEditorRef.value || !aiEditorRef.value.querySelector('.aie-container')) return;
            aiEditorRef.value.querySelector('.aie-container').style.minHeight = mappingProps.minHeight || mappingProps.maxHeight
            aiEditorRef.value.querySelector('.aie-container').style.maxHeight = mappingProps.maxHeight || mappingProps.minHeight
        }

        watch(() => [mappingProps.minHeight, mappingProps.maxHeight], () => {

            InitEditor()
            if (delayList.changeHeight) {
                window.clearTimeout(delayList.changeHeight)
                delayList.changeHeight = null
            }
            delayList.changeHeight = window.setTimeout(() => {
                setEditorHeight()
            }, 200);

        })
        watch(() => mappingProps.selectedToolbar, (newValue, oldValue) => {
            if (newValue && oldValue && JSON.stringify(newValue) != JSON.stringify(oldValue) && !window.readCookie) {

                InitEditor()
            }
        })
        watch(() => [mappingProps.customizeToolbar, mappingProps.isSimple, mappingProps.dense, mappingProps.enableComment, mappingProps.noResize], () => {

            InitEditor()
        })

        watch(() => mappingProps.modelValue, () => {
            if (targetProxy != mappingProps.modelValue && convertColwidthToStyle(targetProxy.replace(/<mark/ig, '<span').replace(/<\/mark>/ig, '</span>')) != mappingProps.modelValue) {
                targetProxy = mappingProps.modelValue

                InitEditor()
            }
        })

        watch(()=> mappingProps.outlineVisible, (value)=>{
          aiEditorInstance && aiEditorInstance.setOutlineVisible(value);
        })

        const numberToRGB = (num) => {
            // 确保输入是一个字符串，以便我们可以处理前导零
            let numStr = num.toString();

            // 将数字转换为二进制字符串
            let binaryStr = parseInt(numStr.replace(/-/ig, ''), 16).toString(2);

            // 确保二进制字符串长度为24位，不足的前面补0
            binaryStr = binaryStr.padStart(24, '0');

            // 将24位二进制字符串分成三个8位段
            let red = parseInt(binaryStr.substring(0, 8), 2);
            let green = parseInt(binaryStr.substring(8, 16), 2);
            let blue = parseInt(binaryStr.substring(16, 24), 2);

            // 将十进制值转换为RGB格式的字符串
            return `rgb(${red}, ${green}, ${blue})`;
        }
        const deleteCommemt = (target, id) => {
            let deleteList = []
            let delateData = target.find(item => item.id == id)

            if (delateData) {
                deleteList.push(delateData)
                delateData.isDelete = true
                deleteCommemtList.value.push(delateData)
                if (delateData.children) {
                    delateData.children.forEach(item => {
                        item.isDelete = true
                        deleteCommemtList.value.push(item)
                    })
                }
                emit('commentChange', {
                    type: 'delete',
                    content: delateData
                })
                return target
            }
            target = target.filter(item => item.id != id)
            target.forEach(item => {
                if (item.children) {
                    item.children = deleteCommemt(item.children, id)
                }
            })
            return target
        }
        const formatComment = () => {
            allComments.value = allComments.value.map(item => {
                let res = {}
                for (let i in item) {
                    let key = Object.values(mappingData).indexOf(i)
                    if (key != -1) {
                        if (Object.keys(mappingData)[key] == 'content') {
                            try {
                                let content = JSON.parse(item[i])
                                if (isObject(content)) {
                                    res = Object.assign(res, content)
                                } else {
                                    res[Object.keys(mappingData)[key]] = item[i]
                                }

                            } catch (error) {
                                res[Object.keys(mappingData)[key]] = item[i]
                            }
                        } else {
                            res[Object.keys(mappingData)[key]] = item[i]
                        }

                    }

                }
                res.mainColor = numberToRGB(item.Creator || (Math.random() * 100000000000))
                return res
            })
        }
        const generateChildrenComment = (items, rootId = null) => {

            // 存储树结构
            const tree = [];

            // 查找父节点的函数
            function findParent(node, parentId) {
                return node.id === parentId;
            }

            // 为每个节点找到父节点并构建树
            function addChild(parent, child) {
                // 如果父节点不存在children属性，则添加该属性
                if (!parent.children) {
                    parent.children = [];
                }
                // 将子节点添加到父节点的children数组中
                parent.children.push(child);
            }

            // 遍历所有节点，为每个节点找到父节点并构建树
            items.forEach(item => {
                // 如果是根节点，直接添加到树数组中
                if (item.pid === rootId) {
                    tree.push(item);
                } else {
                    // 否则，找到父节点并将当前节点作为子节点添加
                    const parent = items.find(node => item.pid ? findParent(node, item.pid) : false);
                    if (parent) {
                        addChild(parent, item);
                    } else {
                        // 如果没有找到父节点，那么将当前节点作为根节点处理
                        tree.push(item);
                    }
                }
            });
            return tree;
        }
        let commentStatus = 'hide'
        const formatFileName = (name) => {
            name = name.replace(/[!@#$%^&*()_+\-={}\[\];',.`~\.]+/g, '');
            name = name.replace(/[！@#￥%……&（）——+-={}：“《》？【】、；‘，。·~]+/g, '');
            name = name + new Date().format('yyyyMMddhhmmss')
            return name
        }

        const defaultAiRole =
          '你是资深技术文档工程师、IT专家精通所有研发阶段的各种文档设计和编写，拥有丰富的文档写作经验，对文档的结构、内容、格式、层级、标题、段落、图表、表格、公式、代码等方面都有深入的理解和掌握。';
        const __initEditor__ = async () => {
            /**
             * 加载结束
             */
            //如果有配置，重写默认
            let reWriteConfig = {
                ai: {
                    chatConfig: {
                       role: mappingProps.aiRole || defaultAiRole,
                       enableReference: mappingProps.enableAiReference,
                       format: mappingProps.aiFormat,
                       constraints: mappingProps.aiConstraints,
                       addReference: (cb) => {
                         if (!mappingProps.enableAiReference) {
                           return;
                         }
                         emit('addReference', cb)
                       }
                    },
                    enable: mappingProps.enableAi,
                    models: {
                        openai: {
                            endpoint: '',
                            model: '',
                            apiKey: '',// 开源限制，不对外直接提供
                        },
                    },
                    commands: mappingProps.enableAi ? undefined : [],
                    bubblePanelEnable: mappingProps.enableAi,
                },
            }
            if (mappingProps.queryAllComments && mappingProps.commentDataSource) {
                reWriteConfig = Object.assign(reWriteConfig, {
                    comment: {
                        enable: mappingProps.enableComment,
                        enableWithEditDisable: true,

                        onCommentActivated: (t) => {
                            //当评论被激活时，鼠标选中了（或点击）了某段被标识的内容
                        },
                        queryAllComments: async () => {
                            allComments.value = await mappingProps.queryAllComments()
                            if (!allComments.value) allComments.value = []
                            return _.cloneDeep(allComments.value)
                        },
                        queryCommentsByIds: async (Ids) => {
                            //异步会有问题
                            if (!(Ids && Ids.length)) return
                            allComments.value.forEach(element => {
                                if (!Ids.includes(element.id)) {
                                    element.isShow = true
                                }
                            })
                            return allComments.value.filter(item => !item.isShow)

                        },
                        onCommentCreate: (id, content, pid) => {
                            console.log("reWriteConfig onCommentCreate---->", id, content, pid);

                            const r = {
                                id,
                                pid,
                                account: window.Session?.UserName,
                                avatar: window.Session?.Avatar,
                                mainColor: numberToRGB(window.Session?.UserId || (Math.random() * 100000000000)),
                                createdAt: new Date().format('yyyy/MM/dd hh:mm:ss'),
                                content,
                                //reference:document.querySelector(`[data-comment-id='${pid||id}']`)?.textContent,
                                isNew: true
                            };
                            setTimeout(() => {
                                r.reference = ''
                                let all = document.querySelectorAll(`span[class*="${pid || id}"]`)
                                for (
                                    let i = 0; i < all.length; i++
                                ) {
                                    r.reference += all[i].innerText
                                }
                                addCommemtList.value.push(r)
                                //如果存在pid 往父节点存储
                                if (pid) {
                                    const parentNode = allComments.value.find(item => item.id == pid);
                                    if (parentNode) {
                                        parentNode.children ? parentNode.children.unshift(r) : (parentNode.children = [r])
                                    }
                                } else {
                                    allComments.value.unshift(r)
                                };

                            }, 1000);

                            emit('commentChange', {
                                type: 'add',
                                content: r
                            })
                            return (
                                new Promise((resolve) => {
                                    resolve(r);
                                })
                            );
                        },
                        onCommentDelete: (t) => (
                            deleteCommemt(allComments.value, t)
                        ),
                    }
                })
            }
            if (window.TeldWebConfig) {
                Object.assign(
                    reWriteConfig, {
                      image: {
                          allowBase64: true,
                          defaultSize: 350,
                          onResize: ({aiEditor}) => {
                            console.log('image.onResize')
                            /** 为了解决图片尺寸无法保持住的问题 */
                            onChange(aiEditor);
                          },
                          uploadUrl: window.TeldWebConfig.ResourceURL + '/api/resource/UploadImgByMultipart',
                          uploadFormName: "image", //上传时的文件表单名称
                          uploadHeaders: {
                              'Accept': '*/*',

                              'SRC': 'Resource',
                          },
                          uploader: (file, uploadUrl, headers, formName) => {
                              //可自定义图片上传逻辑
                              const formData = new FormData();
                              return new Promise(async (resolve, reject) => {
                                  let filenamearr = file.name.split('.');
                                  let extension = filenamearr.pop()
                                  let fileName = filenamearr.join('.')
                                  fileName = formatFileName(fileName)
                                  file.ext1 = fileName + '.' + extension
                                  formData.append(file.name, file);
                                  formData.append(file.name, JSON.stringify({
                                      Name: fileName,
                                      Extension: extension,
                                      pathid: '101',
                                      CustomFileName: fileName,
                                  }));
                                  if(TFF?.common?.ajax?.refreshToken){
                                      await TFF.common.ajax.refreshToken()
                                  }

                                  fetch(uploadUrl, {
                                      method: "post",
                                      headers: { 'Accept': 'multipart/form-data', ...headers,  'X-Token': window.readCookie && window.readCookie('telda')},
                                      body: formData
                                  }).then(json => {
                                      resolve(json);
                                  }).catch((error) => { reject(error) })
                              })
                          },
                          uploaderEvent: {
                              onUploadBefore: (file, uploadUrl, headers) => {
                                  //监听图片上传之前，此方法可以不用回任何内容，但若返回 false，则终止上传
                              },
                              onSuccess: (file, response) => {
                                  //监听图片上传成功
                                  //注意：
                                  // 1、如果此方法返回 false，则图片不会被插入到编辑器
                                  // 2、可以在这里返回一个新的 json 给编辑器
                                  /**
                                   * TODO 需要组件支持返回的文件地址，目前没有返回文件地址
                                   */
                                  return {
                                      "errorCode": 0,
                                      "data": {
                                          "src": `${window.TeldWebConfig.ResourceURL}/teldimage/101/${file.ext1 || file.name}`,
                                          "alt": file.name
                                      }
                                  }
                              },
                              onFailed: (file, response) => {
                                  //监听图片上传失败，或者返回的 json 信息不正确
                              },
                              onError: (file, error) => {
                                  //监听图片上传错误，比如网络超时等
                              },
                          },
                          bubbleMenuItems: ["AlignLeft", "AlignCenter", "AlignRight", "delete"]
                      },
                      video: {
                          onResize: ({aiEditor}) => {
                            /** 为了解决视频调整尺寸无法保持住的问题 */
                            onChange(aiEditor);
                          },
                          uploadUrl: window.TeldWebConfig.ResourceURL + '/api/resource/UploadDocByMultipart',
                          uploadFormName: "video", //上传时的文件表单名称
                          uploadHeaders: {
                              'Accept': '*/*',

                              'SRC': 'Resource',
                          },
                          uploader: (file, uploadUrl, headers, formName) => {
                              //可自定义视频上传逻辑
                              const formData = new FormData();
                              return new Promise(async (resolve, reject) => {
                                  let filenamearr = file.name.split('.');

                                  let extension = filenamearr.pop()
                                  let fileName = filenamearr.join('.')
                                  fileName = formatFileName(fileName)
                                  file.ext1 = fileName + '.' + extension
                                  formData.append(file.name, file);
                                  formData.append(file.name, JSON.stringify({
                                      Name: fileName,
                                      Extension: extension,
                                      pathid: '101',
                                      CustomFileName: fileName,
                                  }));
                                  if(TFF?.common?.ajax?.refreshToken){
                                      await TFF.common.ajax.refreshToken()
                                  }

                                  fetch(uploadUrl, {
                                      method: "post",
                                      headers: { 'Accept': 'multipart/form-data', ...headers,  'X-Token': window.readCookie && window.readCookie('telda')},
                                      body: formData
                                  }).then(json => {
                                      resolve(json);
                                  }).catch((error) => { reject(error) })
                              })
                          },
                          uploaderEvent: {
                              onUploadBefore: (file, uploadUrl, headers) => {
                                  //监听视频上传之前，此方法可以不用回任何内容，但若返回 false，则终止上传

                              },
                              onSuccess: (file, response) => {
                                  //监听视频上传成功
                                  //注意：
                                  // 1、如果此方法返回 false，则视频不会被插入到编辑器
                                  // 2、可以在这里返回一个新的 json 给编辑器
                                  return {
                                      "errorCode": 0,
                                      "data": {
                                          "src": `${window.TeldWebConfig.ResourceURL}/telddoc/101/${file.ext1 || file.name}`,
                                          // "poster": "http://your-domain.com/poster.jpg"
                                      }
                                  }
                              },
                              onFailed: (file, response) => {
                                  //监听视频上传失败，或者返回的 json 信息不正确
                              },
                              onError: (file, error) => {
                                  //监听视频上传错误，比如网络超时等
                              },
                          }
                      },
                      attachment: {
                          uploadUrl: window.TeldWebConfig.ResourceURL + '/api/resource/UploadDocByMultipart',
                          uploadFormName: "attachment", //上传时的文件表单名称
                          uploadHeaders: {
                              'Accept': '*/*',
                              'SRC': 'Resource',
                          },
                          uploader: (file, uploadUrl, headers, formName) => {
                              //可自定义视频上传逻辑
                              const formData = new FormData();
                              return new Promise(async (resolve, reject) => {
                                  let filenamearr = file.name.split('.');
                                  let extension = filenamearr.pop()
                                  let fileName = filenamearr.join('.')
                                  fileName = formatFileName(fileName)
                                  file.ext1 = fileName + '.' + extension
                                  formData.append(file.name, file);
                                  formData.append(file.name, JSON.stringify({
                                      Name: fileName,
                                      Extension: extension,
                                      pathid: '101',
                                      CustomFileName: fileName,
                                  }));
                                  if(TFF?.common?.ajax?.refreshToken){
                                      await TFF.common.ajax.refreshToken()
                                  }

                                  fetch(uploadUrl, {
                                      method: "post",
                                      headers: { 'Accept': 'multipart/form-data', ...headers,  'X-Token': window.readCookie && window.readCookie('telda')},
                                      body: formData
                                  }).then(json => {
                                      resolve(json);
                                  }).catch((error) => { reject(error) })
                              })
                          },
                          uploaderEvent: {
                              onUploadBefore: (file, uploadUrl, headers) => {
                                  //监听视频上传之前，此方法可以不用回任何内容，但若返回 false，则终止上传

                              },
                              onSuccess: (file, response) => {
                                  //监听视频上传成功
                                  //注意：
                                  // 1、如果此方法返回 false，则视频不会被插入到编辑器
                                  // 2、可以在这里返回一个新的 json 给编辑器
                                  return {
                                      "errorCode": 0,
                                      "data": {
                                          "href": `${window.TeldWebConfig.ResourceURL}/telddoc/101/${file.ext1 || file.name}`,
                                          "fileName": file.name
                                      }
                                  }
                              },
                              onFailed: (file, response) => {
                                  //监听视频上传失败，或者返回的 json 信息不正确
                              },
                              onError: (file, error) => {
                                  //监听视频上传错误，比如网络超时等
                              },
                          }
                      },
                    }
                )
            }
            if (aiEditorInstance) {
                destroyEditor();
            }
            aiEditorInstance = createAiEditor(
              aiEditorRef.value,
              props,
              {
                draggable: !mappingProps['noResize'],

                commentEnable: mappingProps.enableComment,
                placeholder: mappingProps.placeholder || $q.lang.editorV2['editor-placeholder'],
                ...reWriteConfig,
                onChange,
                onBlur,
                content: formatEditorData(
                  mappingProps.modelValue || mappingProps.defaultValue,
                ),
                textSelectionBubbleMenu: {
                  enable: true,
                  items: [
                    mappingProps.enableAi ? 'ai' : undefined,
                    'Bold',
                    'Italic',
                    'Underline',
                    'Strike',
                    'code',
                    'comment',
                  ].filter(n => !!n),
                },
                isMobile,
                editable: !mappingProps.readonly,
                fontFamily: {
                  values: [
                    { name: '阿里巴巴普惠体', value: 'AlibabaPuHuiTi' },
                    { name: '宋体', value: 'SimSun' },
                    { name: '仿宋', value: 'FangSong' },
                    { name: '黑体', value: 'SimHei' },
                    { name: '楷体', value: 'KaiTi' },
                    { name: '微软雅黑', value: 'Microsoft YaHei' },
                    { name: '方正仿宋简体_GBK', value: 'FangSong_GB2312' },
                    { name: 'Arial', value: 'Arial' },
                  ],
                },
                footerPoweredText: (count) => {
                  // return `${aiEditorInstance.getText().length}个字`;
                  return `${count}个字`;
                },
                lang: 'template',
                i18n: {
                  template: {
                    ...$q.lang.editorV2,
                  },
                },
                // contentRetentionKey:mappingProps.instanceCode,
                // contentRetention:true
                outline: {
                  visible: mappingProps.outlineVisible,
                  includeLevels: mappingProps.outlineIncludeLevels ? Array.isArray(
                    mappingProps.outlineIncludeLevels,
                  )
                    ? mappingProps.outlineIncludeLevels
                    : mappingProps.outlineIncludeLevels.split(',').map(n=>parseInt(n)) : undefined,
                  position: mappingProps.outlinePosition,
                  onVisibleChange: visible => {
                    mappingProps.outlineVisible = visible;
                    emit('update:outlineVisible', visible);
                  },
                },
              },
              {
                changeCommentStatus: (editor) => {
                  if (commentStatus == 'show') {
                    hideComment();
                    commentStatus = 'hide';
                  } else {
                    showComment();
                    editor.commands().recalculateCommentPositions();
                    commentStatus = 'show';
                  }
                },
              },
              $q,
            );

            if (delayList.init) {
                window.clearTimeout(delayList.init)
                delayList.init = null
            }
            delayList.init = window.setTimeout(() => {
                setEditorHeight()

                editorText.value = aiEditorInstance && aiEditorInstance.getText()
                if (!isFirstLoad) return
                if (editorText.value) { onChange(aiEditorInstance) }

                onChangeDoc();

                setTimeout(() => {
                    if (mappingProps.autofocus) {
                        isFirstLoad = false
                        setFocus()
                    }
                    unRegistorPreview()
                    registorPreview()
                }, /*1000*/);
            }, /*500*/);
        }
        const InitEditor = debounce(async () => {
          /**
           * 需要前置请求，否在在内部异步加载有问题
           */
          if (
            (mappingProps.modelValue || mappingProps.defaultValue) &&
            mappingProps.queryAllComments &&
            mappingProps.commentDataSource &&
            mappingProps.enableComment
          ) {
            isLoading.value = true;
            let data = null;
            try {
              data = await mappingProps.queryAllComments();
            } catch (error) {
              console.log(error);
            }

            allComments.value = data?.List || [];
            if (!allComments.value) allComments.value = [];
            formatComment();
            allComments.value = generateChildrenComment(allComments.value);
            isLoading.value = false;
          }

          __initEditor__();
        }, 300, { leading : true, trailing: true})
        const registorPreview = () => {
            console.log('registorPreview', tEditorRef.value)
            tEditorRef.value.addEventListener('dblclick', openViewPreview, true)
        }
        const unRegistorPreview = () => {
            tEditorRef.value.removeEventListener('dblclick', openViewPreview)
        }
        const openViewPreview = (e) => {
            if (e.target.tagName.toLowerCase() === 'img') {

                let allImg = tEditorRef.value.querySelectorAll('img')
                srcList.value = Array.from(allImg).map(item => item.src)
                previewSrc.value = e.target.src
                const previwer = imagePreviewRef.value;
                if (previwer) {
                    previwer.open(e.target.src);
                }
            }
        }
        const destroyEditor = () => {
            // return new Promise((resolve) => {
            //     aiEditorInstance?.destroy()
            //     setTimeout(() => {
            //         aiEditorInstance = null
            //         aiEditor.value.innerHTML = ''
            //         resolve()
            //     }, 100);

            // })

            aiEditorInstance?.destroy();
            aiEditorInstance = null;
        }
        watch(() => [mappingProps.readonly, mappingProps.enableAi], () => {
            InitEditor()
            // aiEditorInstance && aiEditorInstance.setEditable(!mappingProps.readonly)
        })
        onMounted(async () => {
            await nextTick();
            try {
                InitEditor()
            } catch (error) {
                eval('console.log(error)')
            }
            // unRegistorPreview()
        });

        return () => {
            return (
                <div class={[
                    't-editor_div',
                    mappingProps.labelPosition == 'top' && 'tr-editor-default-top',
                    mappingProps.readonly && 'tr-editor-readonly',
                    (mappingProps.stillShowHeader || isMobile) ? 'tr-editor-still-show-header' : null,
                ]}
                    ref={tEditorRef}
                    v-show={mappingProps.visible}
                    {...attrs}
                    tabIndex='-1'>

                    <LabelPrefixWraper
                        required={mappingProps.required}
                        label={mappingProps.label}
                        labelProps={{ class: 'editor-title' }}
                        hideLabel={mappingProps.hideLabel}
                        labelPosition={mappingProps.labelPosition}
                        helpConf={mappingProps.helpConf}
                        readonly={mappingProps.readonly}
                        helpTooltip={mappingProps.helpTooltip}
                        helpPlacement={mappingProps.helpPlacement}
                        helpMore={mappingProps.helpMore}
                        helpMorePopup={mappingProps.helpMorePopup}
                        helpMoreLink={mappingProps.helpMoreLink}
                        helpMoreLinkHrefStatic={mappingProps.helpMoreLinkHrefStatic}
                        helpMoreLinkHrefExp={mappingProps.helpMoreLinkHrefExp}
                    ></LabelPrefixWraper>

                    <div ref={aiEditorRef} class={displayedErrorHint.value ? 'error_message  aie-theme-light' : 'aie-theme-light'} style={`max-height:${mappingProps.maxHeight}`}></div>
                    <div class="">
                      <t-inner-loading showing={isLoading}>
                        <t-spinner size="20px" color="primary" />
                      </t-inner-loading>
                    </div>
                    {/*  必填校验显示  */}
                    <div v-show={displayedErrorHint.value} class='u-error-message'>
                        {errorHint.value}
                    </div>
                    {(() => {
                        if (props.enableComment && props.enableBottomComment) {
                            return <commentManage
                                enableBottomComment={props.enableBottomComment}
                                enableComment={props.enableComment}
                                onAddComment={(e) => {
                                    const str = decodeURIComponent(e.content);
                                    const regex = /<span pid="([^"]*)"/;
                                    let pid = str.match(regex);
                                    if (pid && pid[1]) {
                                        pid = pid[1]
                                    } else {
                                        pid = ''
                                    }


                                    const r = {
                                        id: Funcs.Guid(),
                                        pid: pid,
                                        account: window.Session?.UserName,
                                        avatar: window.Session?.Avatar,
                                        mainColor: numberToRGB(window.Session?.UserId || (Math.random() * 100000000000)),
                                        createdAt: new Date().format('yyyy/MM/dd hh:mm:ss'),
                                        content: e.content,
                                        //reference:document.querySelector(`[data-comment-id='${pid||id}']`)?.textContent,
                                        isNew: true
                                    };
                                    if (pid) {
                                        const parentNode = allComments.value.find(item => item.id == pid);
                                        if (parentNode) {
                                            parentNode.children ? parentNode.children.unshift(r) : (parentNode.children = [r])
                                        }
                                    } else {
                                        allComments.value.unshift(r)
                                    };

                                    addCommemtList.value.unshift(r)
                                    e.onSucceed()
                                    emit('commentChange', {
                                        type: 'add',
                                        content: r
                                    })
                                }}
                                onDeleteComment={(target) => {
                                    deleteCommemt(allComments.value, target.id)
                                }}
                                allComments={allComments}></commentManage>
                        }
                    })()}
                    <t-image-preview ref={imagePreviewRef} v-model={previewSrc.value} src-list={srcList.value} />

                </div>
            );
        };
    },
});
